package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.*;
import com.atguigu.exam.mapper.*;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.AiPaperVo;
import com.atguigu.exam.vo.PaperVo;
import com.atguigu.exam.vo.RuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;

/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {

    @Autowired
    private PaperMapper paperMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private PaperQuestionMapper paperQuestionMapper;

    @Autowired
    private QuestionAnswerMapper questionAnswerMapper;

    @Autowired
    private QuestionChoiceMapper questionChoiceMapper;

    @Autowired
    private PaperQuestionService paperQuestionService;

    @Autowired
    private ExamRecordMapper examRecordMapper;
    /**
     * 手动创建试卷
     * @param paperVo 试卷创建参数
     * @return 创建完成的试卷对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Paper createPaper(PaperVo paperVo) {
        if (paperVo == null) {
            throw new IllegalArgumentException("试卷参数不能为空");
        }
        if (ObjectUtils.isEmpty(paperVo.getName())) {
            throw new IllegalArgumentException("试卷名称不能为空");
        }

        Map<Integer, BigDecimal> questionScoreMap = paperVo.getQuestions();
        if (questionScoreMap == null || questionScoreMap.isEmpty()) {
            throw new IllegalArgumentException("试卷必须至少包含一道题目");
        }

        Paper paper = new Paper();
        paper.setName(paperVo.getName());
        paper.setDescription(paperVo.getDescription());
        paper.setDuration(paperVo.getDuration());
        paper.setStatus("DRAFT");

        BigDecimal totalScore = BigDecimal.ZERO;
        for (Map.Entry<Integer, BigDecimal> entry : questionScoreMap.entrySet()) {
            if (entry.getKey() == null) {
                throw new IllegalArgumentException("题目ID不能为空");
            }
            BigDecimal score = entry.getValue();
            if (score == null) {
                throw new IllegalArgumentException("题目分数不能为空");
            }
            totalScore = totalScore.add(score);
        }
        paper.setTotalScore(totalScore);
        paper.setQuestionCount(questionScoreMap.size());

        boolean saved = save(paper);
        if (!saved || paper.getId() == null) {
            throw new RuntimeException("试卷保存失败");
        }

        Long paperId = paper.getId();
        List<Long> questionIds = questionScoreMap.keySet().stream()
                .map(Integer::longValue)
                .toList();

        List<Question> questions = questionMapper.selectBatchIds(questionIds);
        if (questions == null || questions.size() != questionIds.size()) {
            throw new IllegalArgumentException("存在无效的题目ID，请检查题目选择");
        }

        Map<Long, Question> questionMap = questions.stream()
                .collect(Collectors.toMap(Question::getId, q -> q));

        int paperIdInt = Math.toIntExact(paperId);
        for (Map.Entry<Integer, BigDecimal> entry : questionScoreMap.entrySet()) {
            Long questionId = entry.getKey().longValue();
            Question question = questionMap.get(questionId);
            if (question == null) {
                throw new IllegalArgumentException("题目ID不存在：" + entry.getKey());
            }

            BigDecimal score = entry.getValue();
            PaperQuestion paperQuestion = new PaperQuestion();
            paperQuestion.setPaperId(paperIdInt);
            paperQuestion.setQuestionId(questionId);
            paperQuestion.setScore(score);
            paperQuestionMapper.insert(paperQuestion);

            question.setPaperScore(score);
        }

        return getPaperById(Math.toIntExact(paperId));
    }

    /**
     * AI智能组卷
     * @param aiPaperVo AI组卷参数
     * @return 创建完成的试卷对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Paper createPaperWithAI(AiPaperVo aiPaperVo) {
        if (aiPaperVo == null) {
            throw new IllegalArgumentException("AI组卷参数不能为空");
        }
        if (ObjectUtils.isEmpty(aiPaperVo.getName())) {
            throw new IllegalArgumentException("试卷名称不能为空");
        }

        List<RuleVo> rules = aiPaperVo.getRules();
        if (rules == null || rules.isEmpty()) {
            throw new IllegalArgumentException("AI组卷规则不能为空");
        }

        Paper paper = new Paper();
        paper.setName(aiPaperVo.getName());
        paper.setDescription(aiPaperVo.getDescription());
        paper.setDuration(aiPaperVo.getDuration());
        paper.setStatus("DRAFT");
        paper.setTotalScore(BigDecimal.ZERO);
        paper.setQuestionCount(0);

        boolean saved = save(paper);
        if (!saved || paper.getId() == null) {
            throw new RuntimeException("试卷保存失败");
        }

        Long paperId = paper.getId();
        int paperIdInt = Math.toIntExact(paperId);

        BigDecimal totalScore = BigDecimal.ZERO;
        int totalQuestionCount = 0;
        Set<Long> selectedQuestionIds = new LinkedHashSet<>();
        List<PaperQuestion> relationList = new ArrayList<>();

        for (RuleVo rule : rules) {
            if (rule == null) {
                continue;
            }
            if (rule.getType() == null) {
                throw new IllegalArgumentException("题目类型不能为空");
            }

            Integer ruleCount = rule.getCount();
            if (ruleCount == null || ruleCount <= 0) {
                continue;
            }

            Integer perScore = rule.getScore();
            if (perScore == null || perScore <= 0) {
                throw new IllegalArgumentException("题目分值必须大于0");
            }

            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(Question::getId);
            queryWrapper.eq(Question::getType, rule.getType().name());
            queryWrapper.eq(Question::getIsDeleted, 0);

            if (rule.getCategoryIds() != null && !rule.getCategoryIds().isEmpty()) {
                List<Long> categoryIds = rule.getCategoryIds().stream()
                        .filter(Objects::nonNull)
                        .map(Integer::longValue)
                        .toList();
                if (!categoryIds.isEmpty()) {
                    queryWrapper.in(Question::getCategoryId, categoryIds);
                }
            }

            List<Long> candidateIds = questionMapper.selectList(queryWrapper).stream()
                    .map(Question::getId)
                    .filter(Objects::nonNull)
                    .filter(id -> !selectedQuestionIds.contains(id))
                    .toList();

            if (candidateIds.isEmpty()) {
                continue;
            }

            List<Long> shuffledIds = new ArrayList<>(candidateIds);
            Collections.shuffle(shuffledIds);

            int actualCount = Math.min(ruleCount, shuffledIds.size());
            if (actualCount <= 0) {
                continue;
            }

            BigDecimal scorePerQuestion = BigDecimal.valueOf(perScore);
            List<Long> finalIds = shuffledIds.subList(0, actualCount);
            for (Long questionId : finalIds) {
                if (questionId == null) {
                    continue;
                }
                if (!selectedQuestionIds.add(questionId)) {
                    continue;
                }
                PaperQuestion relation = new PaperQuestion();
                relation.setPaperId(paperIdInt);
                relation.setQuestionId(questionId);
                relation.setScore(scorePerQuestion);
                relationList.add(relation);

                totalQuestionCount++;
                totalScore = totalScore.add(scorePerQuestion);
            }
        }

        if (relationList.isEmpty()) {
            throw new IllegalArgumentException("AI组卷未选出任何题目，请调整组卷规则");
        }

        boolean relationSaved = Db.saveBatch(relationList);
        if (!relationSaved) {
            throw new RuntimeException("试卷题目关联保存失败");
        }

        paper.setQuestionCount(totalQuestionCount);
        paper.setTotalScore(totalScore);
        boolean updated = updateById(paper);
        if (!updated) {
            throw new RuntimeException("试卷信息更新失败");
        }

        return getPaperById(paperIdInt);
    }

    /**
     * 获取试卷详情（包含题目、选项、答案及分值）
     * @param id 试卷ID
     * @return 试卷详情
     */
    @Override
    public Paper customPaperDetailById(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("试卷ID不能为空");
        }

        Paper paper = paperMapper.selectById(id);
        if (paper == null) {
            return null;
        }

        LambdaQueryWrapper<PaperQuestion> relationWrapper = new LambdaQueryWrapper<>();
        relationWrapper.eq(PaperQuestion::getPaperId, id);
        relationWrapper.eq(PaperQuestion::getIsDeleted, 0);
        relationWrapper.orderByAsc(PaperQuestion::getCreateTime);
        List<PaperQuestion> relations = paperQuestionMapper.selectList(relationWrapper);

        if (relations == null || relations.isEmpty()) {
            paper.setQuestions(Collections.emptyList());
            paper.setQuestionCount(0);
            paper.setTotalScore(BigDecimal.ZERO);
            return paper;
        }

        List<Long> questionIds = relations.stream()
                .map(PaperQuestion::getQuestionId)
                .filter(Objects::nonNull)
                .toList();

        if (questionIds.isEmpty()) {
            paper.setQuestions(Collections.emptyList());
            paper.setQuestionCount(0);
            paper.setTotalScore(BigDecimal.ZERO);
            return paper;
        }

        List<Question> questions = questionMapper.selectBatchIds(questionIds);
        if (questions == null || questions.isEmpty()) {
            paper.setQuestions(Collections.emptyList());
            paper.setQuestionCount(0);
            paper.setTotalScore(BigDecimal.ZERO);
            return paper;
        }

        Map<Long, Question> questionMap = questions.stream()
                .filter(q -> q.getId() != null)
                .collect(Collectors.toMap(Question::getId, q -> q, (a, b) -> a, HashMap::new));

        List<Question> orderedQuestions = new ArrayList<>();
        for (PaperQuestion relation : relations) {
            Question question = questionMap.get(relation.getQuestionId());
            if (question != null) {
                question.setPaperScore(relation.getScore());
                orderedQuestions.add(question);
            }
        }

        if (orderedQuestions.isEmpty()) {
            paper.setQuestions(Collections.emptyList());
            paper.setQuestionCount(0);
            paper.setTotalScore(BigDecimal.ZERO);
            return paper;
        }

        List<Long> orderedIds = orderedQuestions.stream()
                .map(Question::getId)
                .filter(Objects::nonNull)
                .toList();

        if (!orderedIds.isEmpty()) {
            LambdaQueryWrapper<QuestionChoice> choiceWrapper = new LambdaQueryWrapper<>();
            choiceWrapper.in(QuestionChoice::getQuestionId, orderedIds);
            List<QuestionChoice> allChoices = questionChoiceMapper.selectList(choiceWrapper);

            Map<Long, List<QuestionChoice>> choiceMap = new HashMap<>();
            if (allChoices != null) {
                for (QuestionChoice choice : allChoices) {
                    if (choice.getQuestionId() == null) {
                        continue;
                    }
                    choiceMap.computeIfAbsent(choice.getQuestionId(), k -> new ArrayList<>()).add(choice);
                }
                choiceMap.values().forEach(list -> list.sort(Comparator.comparingInt(QuestionChoice::getSort)));
            }

            LambdaQueryWrapper<QuestionAnswer> answerWrapper = new LambdaQueryWrapper<>();
            answerWrapper.in(QuestionAnswer::getQuestionId, orderedIds);
            List<QuestionAnswer> allAnswers = questionAnswerMapper.selectList(answerWrapper);

            Map<Long, QuestionAnswer> answerMap = new HashMap<>();
            if (allAnswers != null) {
                for (QuestionAnswer answer : allAnswers) {
                    if (answer.getQuestionId() != null) {
                        answerMap.put(answer.getQuestionId(), answer);
                    }
                }
            }

            for (Question question : orderedQuestions) {
                List<QuestionChoice> choices = choiceMap.get(question.getId());
                if (choices == null) {
                    choices = Collections.emptyList();
                }
                question.setChoices(choices);
                question.setAnswer(answerMap.get(question.getId()));
            }
        }

        BigDecimal totalScore = relations.stream()
                .map(PaperQuestion::getScore)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        paper.setQuestionCount(orderedQuestions.size());
        paper.setTotalScore(totalScore);
        paper.setQuestions(orderedQuestions);

        return paper;
    }

    @Override
    public Paper customUpdatePaper(Integer id, PaperVo paperVo) {

        //1.校验 （不能发布状态 ， 不能不同id,name相同）
        Paper paper = getById(id);
        if ("PUBLISHED".equals(paper.getStatus())){
            throw new RuntimeException("发布状态下的试卷不允许修改！");
        }
        //校验id name
        LambdaQueryWrapper<Paper> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(Paper::getId, id);
        queryWrapper.eq(Paper::getName,paperVo.getName());
        long count = count(queryWrapper);
        if (count > 0){
            throw new RuntimeException("%s 试卷名字已经存在，请重新修改！".formatted(paperVo.getName()));
        }
        //2.试卷的主体
        BeanUtils.copyProperties(paperVo,paper);
    /*
      状态默认值： DRAFT
      总题目数： question长度
      总分数： question分数的和
     */
        paper.setQuestionCount(paperVo.getQuestions().size());
        paper.setTotalScore(paperVo.getQuestions().values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
        updateById(paper);

        //3. 中间表的批量插入
        paperQuestionService.remove(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId,paper.getId()));
        List<PaperQuestion> paperQuestionList = paperVo.getQuestions().entrySet().stream().
                map(entry -> new PaperQuestion(paper.getId().intValue(), Long.valueOf(entry.getKey()), entry.getValue()))
                .collect(Collectors.toList());

        //4. 中间表的批量插入
        paperQuestionService.saveBatch(paperQuestionList);
        return paper;
    }

    /**
     * 修改试卷状态
     *
     * @param id     试卷ID
     * @param status 状态
     */
    @Override
    public void customUpdatePaperStatus(Integer id, String status) {
        LambdaUpdateWrapper<Paper> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Paper::getId, id);
        updateWrapper.set(Paper::getStatus, status);
        boolean updated = update(updateWrapper);
        if (!updated) {
            throw new RuntimeException("修改试卷状态失败");
        }
    }

    /**
     * 删除试卷
     *
     * @param id 试卷ID
     */
    @Override
    public void customRemoveId(Integer id) {
        //1.不是发布状态
        Paper paper = getById(id);
        if (paper == null || "PUBLISHED".equals(paper.getStatus())){
            throw new RuntimeException("发布状态的试卷不能删除！");
        }
        //2.不能有关联的考试记录
        LambdaQueryWrapper<ExamRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ExamRecord::getExamId,id);
        Long count = examRecordMapper.selectCount(lambdaQueryWrapper);
        if (count > 0){
            throw new RuntimeException("当前试卷：%s 下面有关联 %s条考试记录！无法直接删除！".formatted(id,count));
        }
        //3.删除自身表
        removeById(Long.valueOf(id));
        //4.删除中间表
        paperQuestionService.remove(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId,id));
    }

    /**
     * 获取所有试卷
     *
     * @param name   试卷名称
     * @param status 试卷状态
     * @return 试卷列表
     */
    @Override
    public List<Paper> listPapers(String name, String status) {
        LambdaQueryWrapper<Paper> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!ObjectUtils.isEmpty(name), Paper::getName, name);
        queryWrapper.eq(!ObjectUtils.isEmpty(status), Paper::getStatus, status);

        List<Paper> papers = paperMapper.selectList(queryWrapper);
        return papers;
    }

    /**
     * 根据ID获取试卷
     *
     * @param id 试卷ID
     * @return 试卷
     */
    @Override
    public Paper getPaperById(Integer id) {
        Paper paper = paperMapper.selectById(id);
        if (paper == null) {
            return null;
        }

        LambdaQueryWrapper<PaperQuestion> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PaperQuestion::getPaperId, id);
        queryWrapper.eq(PaperQuestion::getIsDeleted, 0);
        List<PaperQuestion> paperQuestions = paperQuestionMapper.selectList(queryWrapper);

        List<Long> questionsIds = paperQuestions.stream().map(PaperQuestion::getQuestionId).toList();

        if (questionsIds.isEmpty()) {
            paper.setQuestions(List.of());
            return paper;
        }

        List<Question> questions = questionMapper.selectBatchIds(questionsIds);

        // 批量获取所有选择题选项
        List<Long> choiceQuestionIds = questions.stream()
                .filter(q -> "CHOICE".equals(q.getType()))
                .map(Question::getId)
                .toList();
        
        List<QuestionChoice> allChoices = new ArrayList<>();
        if (!choiceQuestionIds.isEmpty()) {
            LambdaQueryWrapper<QuestionChoice> choiceQueryWrapper = new LambdaQueryWrapper<>();
            choiceQueryWrapper.in(QuestionChoice::getQuestionId, choiceQuestionIds);
            allChoices = questionChoiceMapper.selectList(choiceQueryWrapper);
        }
        
        // 批量获取所有题目的答案
        List<QuestionAnswer> allAnswers = new ArrayList<>();
        if (!questionsIds.isEmpty()) {
            LambdaQueryWrapper<QuestionAnswer> answerQueryWrapper = new LambdaQueryWrapper<>();
            answerQueryWrapper.in(QuestionAnswer::getQuestionId, questionsIds);
            allAnswers = questionAnswerMapper.selectList(answerQueryWrapper);
        }

        // 为每个题目设置选项和答案
        for (Question question : questions) {
            // 设置选择题选项
            if ("CHOICE".equals(question.getType())) {
                List<QuestionChoice> choices = allChoices.stream()
                        .filter(c -> c.getQuestionId().equals(question.getId()))
                        .sorted(Comparator.comparingInt(QuestionChoice::getSort))
                        .toList();
                question.setChoices(choices);
            }
            
            // 设置题目答案
            QuestionAnswer answer = allAnswers.stream()
                    .filter(a -> a.getQuestionId().equals(question.getId()))
                    .findFirst()
                    .orElse(null);
            question.setAnswer(answer);
        }

        questions.sort((o1, o2) -> Integer.compare(typeToInt(o1.getType()), typeToInt(o2.getType())));
        paper.setQuestions(questions);

        return paper;
    }

    /**
     * 获取题目类型的排序顺序
     * @param type 题目类型
     * @return 排序序号
     */
    private int typeToInt(String type) {
        switch (type) {
            case "CHOICE": return 1; // 选择题
            case "JUDGE": return 2;  // 判断题
            case "TEXT": return 3;   // 简答题
            default: return 4;       // 其他类型
        }
    }
}